import {Logger as NestLogger, ValidationPipe} from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import {
  ExpressAdapter,
  NestExpressApplication,
} from '@nestjs/platform-express';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config';
import {LoggerService} from "@/common/logger/logger.service";
import { BizFailedExceptionFilter } from "@/common/biz-failed/biz-failed.exception-filter";
import { GlobalInterceptor } from "@/common/interceptor/global.interceptor";
import { json, urlencoded } from 'body-parser';
import { initializeTransactionalContext } from 'typeorm-transactional';

const IS_PRODUCTION = process.env.NODE_ENV === 'prod';

const SWAGGER_PATH = 'swagger';

async function bootstrap() {
  initializeTransactionalContext();

  const nestLogger = new NestLogger();
  const app = await NestFactory.create<NestExpressApplication>(
    AppModule,
    new ExpressAdapter(),
    {
      logger: nestLogger,
      bodyParser: false,
    },
  );

  app.use(json({ limit: '20mb'}))
  app.use(urlencoded({ extended: true, limit: '1mb' }));

  const configService: ConfigService = app.get(ConfigService);

  app.useGlobalPipes(
    new ValidationPipe({
      disableErrorMessages: IS_PRODUCTION,
      transform: true, // 自动转换
      whitelist: true, // 多余参数也报错
      forbidNonWhitelisted: true, // 同上
      transformOptions: {
        enableImplicitConversion: true,
      }
    }),
  ); // 全局接口参数验证+参数转换

  app.useGlobalFilters(new BizFailedExceptionFilter()); // 全局捕获业务失败

  app.useGlobalInterceptors(new GlobalInterceptor(new LoggerService(GlobalInterceptor.name))); // 全局拦截器，日志，结果包装

  if(!IS_PRODUCTION){
    const options = new DocumentBuilder()
      .setTitle(configService.get<string>('npm_package_name') ?? '')
      .setDescription(
        configService.get<string>('npm_package_description') ?? '',
      )
      .setVersion(configService.get<string>('npm_package_version') ?? '')
      .addSecurity('token',{ type: 'apiKey', name: 'token', in: 'header' })
      .build();
    const document = SwaggerModule.createDocument(app, options);
    SwaggerModule.setup(SWAGGER_PATH, app, document);
  }

  await app.listen(configService.get<number>('PORT') ?? 4000, '0.0.0.0');
  nestLogger.log(
    `App listening on ${configService.get<number>('PORT')}, env: ${
      process.env.NODE_ENV ?? 'local'
    }`,
      'NestApplication'
  );

  if (!IS_PRODUCTION) {
    nestLogger.log(
      `Swagger doc setup http://127.0.0.1:${configService.get<number>(
        'PORT',
      )}/${SWAGGER_PATH}`,
        'NestApplication'
    );
  }
}

bootstrap();
